﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Expect.Core.Fixtures;
using DocumentFormat.OpenXml.Wordprocessing;

namespace Expect.Report.Word.Processors
{
    using DocumentFormat.OpenXml;

    public class DescriptionFixtureProcessor : DefaultProcessor, IProcessor<DescriptionFixture>
    {
        public Func<string, string> ResolveStyle { get; set; }

        public override void Apply()
        {
            string currentStyle = Configuration.DescriptionsStyle;
            TextBloc currentbloc = null;

            foreach (var row in Fixture.Rows)
            {
                string rowtext = row.Cells[0].Text;
                string trimmed = rowtext.Trim();

                var bloc = this.GetBloc(trimmed);
                if (bloc != null && currentbloc == null)
                {
                    currentbloc = bloc;
                    currentStyle = bloc.StyleName;
                    continue;
                }

                if (currentbloc != null && trimmed == currentbloc.EndToken)
                {
                    currentbloc = null;
                    currentStyle = Configuration.DescriptionsStyle;
                    continue;
                }

                WriteRow(rowtext, currentStyle);                
            }
        }

        private TextBloc GetBloc(string rowcontent)
        {
            foreach (var bloc in Configuration.Blocs)
            {
                if (bloc.StartToken == rowcontent) return bloc;
            }

            return null;
        }

        private void WriteRow(string rowtext, string currentStyle)
        {
            var par = Document.NewParagraph(ResolveStyle(currentStyle));
            var runs = this.GetRuns(rowtext);
            foreach (var textRun in runs)
            {
                this.WriteRun(par, textRun);
            }
        }

        public List<TextRun> GetRuns(string rowtext)
        {
            var res = new List<TextRun>();            
            StringBuilder buffer = new StringBuilder();
            TextRun currentRun = null;
            for (int i = 0; i < rowtext.Length; i++)
            {
                bool lastchar = (i == rowtext.Length - 1);
                
                if (currentRun == null)
                {
                    bool runfound = false;
                    foreach (var run in Configuration.Runs)
                    {
                        if (!lastchar && rowtext[i] == run.Token && rowtext[i + 1] != ' ' && (i == 0 || rowtext[i - 1] == ' '))
                        {
                            runfound = true;
                            currentRun = run;
                            if (buffer.Length > 0)
                            {
                                var newrun = new TextRun { Text = buffer.ToString() };
                                res.Add(newrun);
                                buffer = new StringBuilder();
                            }
                            break;
                        }
                    }
                    if (runfound)
                        continue;
                }
                
                if (currentRun != null && rowtext[i] == currentRun.Token && (lastchar || !char.IsLetterOrDigit(rowtext[i+1])))
                {
                    var run = currentRun.GetClone(buffer.ToString());
                    res.Add(run);
                    buffer = new StringBuilder();
                    currentRun = null;
                    continue;
                }

                buffer.Append(rowtext[i]);
            }

            if (buffer.Length > 0)
            {
                var newrun = new TextRun { Text = buffer.ToString() };
                res.Add(newrun);                
            }

            return res;
        }

        private void WriteRun(Paragraph par, TextRun textrun)
        {
            Run run = new Run();
            RunProperties props = new RunProperties();
            run.Append(props);
            if (textrun.Bold)
            {
                Bold bld = new Bold();
                props.Append(bld);
            }
            if (textrun.Italic)
            {
                Italic itl = new Italic();
                props.Append(itl);
            }
            if (textrun.Underline)
            {
                Underline ul = new Underline() { Val = UnderlineValues.Single };
                props.Append(ul);
            }
            Text txt = new Text(textrun.Text) { Space = SpaceProcessingModeValues.Preserve };

            run.Append(txt);
            par.Append(run);
        }
    }
}
